from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.linear_model import SGDClassifier
import numpy as np
import matplotlib.pyplot as plt


def threshold(x, d):
    return [1 if xi > d else 0 for xi in x]


def custom_loss(y_true, y_pred):
    y_true = 2.0 * y_true - 1.0
    v = np.maximum(1.0 - y_true * y_pred, 0.0)
    return 10.0 * np.sum(v)


# 加载数据集
breast_cancer = datasets.load_breast_cancer()
x_train, x_test, y_train, y_test = train_test_split(
    breast_cancer.data, breast_cancer.target, test_size=0.3, random_state=420)

# 定义不同的正则化参数
alphas = [0.01, 0.1, 0.5, 1.0]
results = {}

# 训练模型并记录损失
for alpha in alphas:
    model = SGDClassifier(loss='hinge', alpha=alpha, learning_rate='constant', eta0=0.0001, max_iter=10000,
                          random_state=42)
    losses = []

    for epoch in range(10000):
        model.partial_fit(x_train, y_train, classes=np.unique(y_train))
        if epoch % 100 == 0:
            y_pred_train = model.decision_function(x_train)
            cost = custom_loss(y_train, y_pred_train)
            losses.append(cost)
            print(f"alpha={alpha}, epoch={epoch}, cost={cost}")

    # 记录每个 alpha 对应的损失和模型性能
    pred_train = threshold(model.decision_function(x_train), 0)
    pred_test = threshold(model.decision_function(x_test), 0)
    train_accuracy = accuracy_score(y_train, pred_train)
    test_accuracy = accuracy_score(y_test, pred_test)

    results[alpha] = {
        'losses': losses,
        'train_accuracy': train_accuracy,
        'test_accuracy': test_accuracy
    }

# 绘制损失函数收敛曲线（分开显示）
plt.figure(figsize=(12, 8))
for i, alpha in enumerate(alphas):
    plt.subplot(2, 2, i + 1)
    plt.plot(range(0, 10000, 100), results[alpha]['losses'], label=f'alpha={alpha}')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.title(f'Loss Convergence Curve (alpha={alpha})')
    plt.legend()
    plt.grid()

plt.tight_layout()
plt.show()

# 输出不同正则化参数下的模型性能
for alpha in alphas:
    print(f"Alpha={alpha}:")
    print(f"  Train Accuracy: {results[alpha]['train_accuracy']:.4f}")
    print(f"  Test Accuracy: {results[alpha]['test_accuracy']:.4f}")